/*
 * PredicateVertex.java
 *
 * Created on August 23, 2007, 1:23 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package dnbW.queryW.visualW;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 *
 * @author zhouyong
 */
public class PredicateVertex extends DefaultMutableTreeNode{
    
    // <editor-fold defaultstate="collapsed" desc="Static Base Table ID">
    /** a class-wise counter to initialize table ID of each object */
    private static int baseTableId = 0;

    /**
     * Increment base table ID and get the new base table ID
     * @return
     */
    private int getNextTableId(){
        return baseTableId++;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Table ID">
    /**
     * The name of the corresponding table
     */
    private int tableId;

    public int getTableId() {
        return tableId;
    }

    public void setTableId(int tableId) {
        this.tableId = tableId;
    }
    // </editor-fold>

    private int identityTableRowCount;

    String _selfExpression;
    
    private Map<Integer, Long> identityPathMap = new HashMap<Integer, Long>();
    private Set<Integer> deweyOrderSumSet = new HashSet<Integer>();
    
    /** Creates a new instance of PredicateVertex */
    public PredicateVertex() {
        this.setTableId(this.getNextTableId());
    }
    
    public String getPredicateExpression() {
        // Travel all child nodes of the current node, count the number of children and store them
        PredicateVertex[] vchildren = new PredicateVertex[this.getChildCount()];
        int count = 0;
        for(Enumeration em = this.children(); em.hasMoreElements();){
            Object obj = em.nextElement();
            if(obj != null){
                PredicateVertex v = (PredicateVertex)obj;
                vchildren[count++] = v;
            }
        }

        if(count == 0)
            return "";

        if(count == 1)
            return vchildren[0].getPredicateExpression();

        String[] validExp = new String[count];
        int validCount = 0;
        for(int i=0; i<count; i++){
            String exp = vchildren[i].getPredicateExpression();
            if(!"".equals(exp))
                validExp[validCount++] = exp;
        }

        if(validCount == 0)
            return "";

        if(validCount == 1)
            return validExp[0];

        StringBuilder result = new StringBuilder();
        result.append("(");
        for(int i=0; i<validCount - 1; i++){
            result.append(validExp[i]);
            result.append(" " + getSelfExpression() + " ");
        }
        result.append(validExp[validCount - 1]);
        result.append(")");

        return result.toString();
    }
    
    public int lcp(PathOrientedVertex v1, PathOrientedVertex v2){
        int i = 0;
        for(i=0; i < v1.getFullPath().size() && i < v2.getFullPath().size(); i++){
            DefaultMutableTreeNode n1 = v1.getFullPath().get(i);
            DefaultMutableTreeNode n2 = v2.getFullPath().get(i);
            
            if(!n1.toString().equals(n2.toString()))
                break;
        }
        
        return i - 1;
    }
    
    public String getSelfExpression() {
        return _selfExpression;
    }
    
    public String getHumanReadableText(){
        return "";
    }
    
    /**
     * return an empty list of list
     */
    public List<List<PredicateVertex>> getPredicateList(){
        List<PredicateVertex> l1 = new ArrayList<PredicateVertex>();
        List<List<PredicateVertex>> l2 = new ArrayList<List<PredicateVertex>>();
        
        l2.add(l1);
        return l2;
    }
  
    public String getXQuery(PathOrientedVertex path){
        return null;
    }
    
    // note: currently descendant axis is not supported
    public String getQuery(PathOrientedVertex path){
        
        StringBuilder result = new StringBuilder();
        
        for(List<PredicateVertex> list : getPredicateList()){
            
            String automicPath = "";
            
            Map<DefaultMutableTreeNode, List<PredicateVertex>> predicateMap =
                    new LinkedHashMap<DefaultMutableTreeNode, List<PredicateVertex>>();
            
            // init the predicate map
            for(DefaultMutableTreeNode step : path.getFullPath()){
                predicateMap.put(step, new LinkedList<PredicateVertex>());
            }
            for(PredicateVertex predicate : list){
                if(predicate instanceof ComparisonVertex){
                    ComparisonVertex cv = (ComparisonVertex) predicate;
                    int lcp = lcp(cv, path);
                    if(lcp == cv.getFullPath().size() - 1 && lcp == path.getFullPath().size() - 1)
                        predicateMap.get(path.getFullPath().get(lcp - 1)).add(predicate);
                    else
                        predicateMap.get(path.getFullPath().get(lcp)).add(predicate);
                }else{
                    JoinVertex jv = (JoinVertex) predicate;
                    JoinLeafVertex leaf1 = jv.getLeftLeaf();
                    JoinLeafVertex leaf2 = jv.getRightLeaf();
                    
                    int lcp1 = lcp(leaf1, path);
                    int lcp2 = lcp(leaf2, path);
                    
                    int lcp = (lcp1 < lcp2)?lcp1 : lcp2;
                    predicateMap.get(path.getFullPath().get(lcp)).add(predicate);
                }
            }
            // end init predicte map
            
            
            int lcp = 0;
            for(DefaultMutableTreeNode step : predicateMap.keySet()){
                List<PredicateVertex> predicates = predicateMap.get(step);
                automicPath = automicPath + "/" + step.toString();
                
                for(PredicateVertex predicate : predicates){
                    automicPath = automicPath + "[";
                    
                    if(predicate instanceof ComparisonVertex){
                        ComparisonVertex cv = (ComparisonVertex) predicate;
                        
                        StringBuilder sb = new StringBuilder();
                        for(int i=lcp + 1; i<cv.getFullPath().size(); i++){
                            sb.append("/");
                            sb.append(cv.getFullPath().get(i).toString());
                        }
                    
                        if(sb.length() == 0)
                            sb.append(" self::*");
                        if(cv.getOperator().equalsIgnoreCase("like"))
                            sb.append(" = ");
                        else if(cv.getOperator().equalsIgnoreCase("not like"))
                            sb.append(" != ");
                        else
                            sb.append(" " + cv.getOperator() + " ");
                        
                        if("=".equals(cv.getOperator()) || "!=".equals(cv.getOperator())){
                            sb.append("\"");
                            sb.append(cv.getValue());
                            sb.append("\"");
                        }
                        else if("Like".equalsIgnoreCase(cv.getOperator())
                                || cv.getOperator().equalsIgnoreCase("not like")){
                            sb.append("\"%");
                            sb.append(cv.getValue());
                            sb.append("%\"");
                        }
                        else{
                            sb.append(cv.getValue());
                        }
                        
                        sb.append("]");
                        sb.deleteCharAt(0);
                        
                        automicPath = automicPath + sb.toString();
                    }
                    else{
                        // handle join vertex
                        JoinVertex jv = (JoinVertex) predicate;
                        JoinLeafVertex leaf1 = jv.getLeftLeaf();
                        JoinLeafVertex leaf2 = jv.getRightLeaf();
                        
                        StringBuilder sb1 = new StringBuilder();
                        for(int i=lcp + 1; i<leaf1.getFullPath().size(); i++){
                            sb1.append("/" + leaf1.getFullPath().get(i).toString());
                        }
                        sb1.deleteCharAt(0);
                        
                        StringBuilder sb2 = new StringBuilder();
                        for(int i=lcp + 1; i<leaf2.getFullPath().size(); i++){
                            sb2.append("/" + leaf2.getFullPath().get(i).toString());
                        }
                        sb2.deleteCharAt(0);
                        
                        automicPath = automicPath + 
                                sb1.toString() + 
                                " " + 
                                jv.getOperator() + 
                                " " + 
                                sb2.toString() +
                                "]";
                    }
                }
                
                lcp++;
            }
            
            result.append(" | " + automicPath);
        }
        
        result.deleteCharAt(0);
        result.deleteCharAt(0);
        result.deleteCharAt(0);
        return result.toString();
    }

    public String getIdentityTable() {
        return "T" + this.getTableId();
    }

    public int getIdentityTableRowCount() {
        return identityTableRowCount;
    }

    public void setIdentityTableRowCount(int identityTableRowCount) {
        this.identityTableRowCount = identityTableRowCount;
    }

    public Map<Integer, Long> getIdentityPathMap() {
        return identityPathMap;
    }
    
    public Map<Integer, Long> getIdentityPathMapFinal(){
        return Collections.emptyMap();
    }

    public Set<Integer> getDeweyOrderSumSet() {
        return deweyOrderSumSet;
    }
}
